﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Globalization;
using System.Windows.Browser;

namespace WorkflowDesigner
{
    public sealed class Utility
    {
        // 阴影效果用。
        public const double dBlurEffectRadius = 20.0;

        #region 模态窗口支持
        // 调用 aspx 页面，弹出模态窗口
        public static object ShowModalDialog(string strURL, string strArguments, string strFeatures)
        {
            return System.Windows.Browser.HtmlPage.Window.Invoke(
                "showModalDialog",
                strURL, strArguments, strFeatures);
        }

        // 调用 aspx 页面，弹出模态窗口
        public static object ShowModalDialog(string strURL, string strFeatures)
        {
            return ShowModalDialog(strURL, "", strFeatures);
        }
        #endregion

        #region 浏览器客户区尺寸
        /// <summary>
        /// 浏览器客户区宽度
        /// </summary>
        public static double BrowserClientWidth
        {
            get
            {
                //double dWidth = (double)HtmlPage.Window.Eval("document.body.clientWidth");
                return Application.Current.Host.Content.ActualWidth;
            }
        }

        /// <summary>
        /// 浏览器客户区高度
        /// </summary>
        public static double BrowserClientHeight
        {
            get
            {
                //double dWidth = (double)HtmlPage.Window.Eval("document.body.clientHeight");
                return Application.Current.Host.Content.ActualHeight;
            }
        }
        #endregion

        #region Convert Html's RGB Color (#FFFFFF) To Silverlight's Color

        /// <summary>
        /// 将字符串转化为字节数组
        /// </summary>
        /// <param name="strHex"></param>
        /// <returns></returns>
        public static byte[] Hex2Byte(string strHex)
        {
            byte[] bytes = null;
            try
            {
                char[] charHex = strHex.ToUpper().ToCharArray();
                int bytesLength = charHex.Length / 2;
                bytes = new byte[bytesLength];
                if (bytesLength <= 0)
                {
                    return bytes;
                }

                int[] tempBytes = new int[2];

                //循环每次处理两个字符
                for (int i = 0; i < charHex.Length; i = i + 2)
                {
                    tempBytes[0] = HexChar2Int(charHex[i]) << 4 & 0XF0;
                    tempBytes[1] = HexChar2Int(charHex[i + 1]);
                    bytes[i / 2] = (byte)(tempBytes[0] + tempBytes[1]);
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }

            return bytes;
        }

        /// <summary>
        /// 16 位数据
        /// </summary>
        /// <param name="hexChar"></param>
        /// <returns></returns>
        private static int HexChar2Int(char hexChar)
        {
            switch (hexChar)
            {
                case '0':
                    return 0;
                case '1':
                    return 1;
                case '2':
                    return 2;
                case '3':
                    return 3;
                case '4':
                    return 4;
                case '5':
                    return 5;
                case '6':
                    return 6;
                case '7':
                    return 7;
                case '8':
                    return 8;
                case '9':
                    return 9;
                case 'A':
                    return 10;
                case 'B':
                    return 11;
                case 'C':
                    return 12;
                case 'D':
                    return 13;
                case 'E':
                    return 14;
                case 'F':
                    return 15;
                default:
                    return 0;
            }
        }

        /// <summary>
        /// Convert Html's RGB Color (#FFFFFF) To Silverlight's Color
        /// </summary>
        /// <param name="strColor">Html's RGB Color (#FFFFFF)</param>
        /// <returns>Silverlight's Color</returns>
        public static Color GetColor(string strColor)
        {
            if ((strColor != null) && (strColor.Length >= 6))
            {
                try
                {
                    if (strColor.StartsWith("#"))
                    {
                        strColor = strColor.Substring(1);
                    }
                    byte[] bColor = Hex2Byte(strColor);
                    if (bColor.Length >= 3)
                    {
                        return Color.FromArgb(255, bColor[0], bColor[1], bColor[2]);
                    }
                }
                catch
                {
                }
            }
            return Colors.White;
        }

        #endregion

        #region 计算中心坐标到指定点的线段与控件边界的交点

        /// <summary>
        /// 判断某一个点是否在给定的矩形之内
        /// </summary>
        /// <param name="rt">给定的矩形</param>
        /// <param name="pt">某一个点</param>
        /// <returns>判断结果</returns>
        public static bool PtInRect(Rect rt, Point pt)
        {
            if ((pt.X >= rt.Left)
                && (pt.X <= rt.Right)
                && (pt.Y >= rt.Top)
                && (pt.Y <= rt.Bottom)
                )
            {
                return true;
            }
            return false;
        }

        /// <summary>
        /// 计算两点之间的距离
        /// </summary>
        /// <param name="ptFrom"></param>
        /// <param name="ptTo"></param>
        /// <returns></returns>
        public static double GetLength(Point ptFrom, Point ptTo)
        {
            double dTempValue = (ptFrom.X - ptTo.X) * (ptFrom.X - ptTo.X)
                + (ptFrom.Y - ptTo.Y) * (ptFrom.Y - ptTo.Y);
            return Math.Sqrt(dTempValue);
        }

        /// <summary>
        /// 计算中心坐标到指定点的线段与圆形控件边界的交点
        /// 如果指定点在控件中间则返回圆形控件中心坐标
        /// </summary>
        /// <param name="ptCenter">中心坐标</param>
        /// <param name="dRadius">半径</param>
        /// <param name="ptOuter">指定的任意一点</param>
        /// <returns>中心坐标到指定点的线段与圆形控件边界的交点</returns>
        public static Point GetRoundCrossPoint(Point ptCenter, double dRadius, Point ptOuter)
        {
            Point ptResult = ptCenter;
            double dDistance = Utility.GetLength(ptCenter, ptOuter);
            if (dDistance > dRadius)
            {
                // 两点之间距离大于半径，需要重新求点坐标
                ptResult.X = ptCenter.X + (ptOuter.X - ptCenter.X) * dRadius / dDistance;
                ptResult.Y = ptCenter.Y + (ptOuter.Y - ptCenter.Y) * dRadius / dDistance;
            }
            return ptResult;
        }

        /// <summary>
        /// 判断一个点(ptTest)是否在给定的线段上
        /// 不要求精确的落在线段上，允许存在微小误差
        /// </summary>
        /// <param name="ptFrom"></param>
        /// <param name="ptTo"></param>
        /// <param name="ptTest"></param>
        /// <returns></returns>
        public static bool IsPointInLine(Point pt1, Point pt2, Point ptTest)
        {
            bool isInLine = false;
            double dLengthAB = GetLength(pt1, pt2);
            double dLengthAO = GetLength(pt1, ptTest);
            double dLengthOB = GetLength(ptTest, pt2);
            // 如果 ptTest 在 ptFrom 和 ptTo 连成的线段上
            // 两点之间直线最短,即使有误差,也一定会有 dLengthAO + dLengthOB >= dLengthAB
            double dError = dLengthAO + dLengthOB - dLengthAB;
            if (dError < 3.0)
            {
                // 允许误差为3个像素
                isInLine = true;
            }
            return isInLine;
        }

        /// <summary>
        /// 计算两条线段的交点，给出了A和B两线段各自的头尾坐标
        /// </summary>
        /// <param name="pt1">线段头坐标</param>
        /// <param name="pt2">线段尾坐标</param>
        /// <param name="pt3">线段头坐标</param>
        /// <param name="pt4">线段尾坐标</param>
        /// <returns>线段的交点</returns>
        public static Point GetCrossPoint
            (Point pt1, Point pt2, Point pt3, Point pt4)
        {
            // 默认没有交点, 也就是说交于无穷远处, 所以给出 double.NaN
            Point ptCross = new Point(double.NaN, double.NaN);
            double dTemp1 = (pt4.X - pt3.X) * (pt2.Y - pt1.Y);
            double dTemp2 = (pt2.X - pt1.X) * (pt4.Y - pt3.Y);
            // 先判断是否平行
            if (dTemp1 != dTemp2)
            {
                // 若不平行, 则求其所在直线的交点(dX,dY) 
                double dX = ((pt2.X - pt1.X) * (pt4.X - pt3.X) * (pt3.Y - pt1.Y)
                    + dTemp1 * pt1.X - dTemp2 * pt3.X) / (dTemp1 - dTemp2);
                double dY = ((pt2.Y - pt1.Y) * (pt4.Y - pt3.Y) * (pt3.X - pt1.X)
                    + dTemp2 * pt1.Y - dTemp1 * pt3.Y) / (dTemp2 - dTemp1);
                // 判断(dX,dY)是否为线段上的点 
                Point ptResult = new Point(dX, dY);
                if (IsPointInLine(pt1, pt2, ptResult) && IsPointInLine(pt3, pt4, ptResult))
                {
                    // 都成立就说明ptResult是所求的线段上的交点了, 否则它们无交点
                    ptCross = ptResult;
                }
            }
            return ptCross;
        }

        /// <summary>
        /// 计算菱形控件中心到指定点的线段与菱形控件边界的交点
        /// 如果指定点在菱形控件中间则返回菱形控件中心坐标
        /// </summary>
        /// <param name="ptCenter">中心坐标</param>
        /// <param name="dWidth">控件宽度</param>
        /// <param name="dHeight">控件高度</param>
        /// <param name="ptOuter">指定的任意一点</param>
        /// <returns>中心坐标到指定点的线段与菱形控件边界的交点</returns>
        public static Point GetLozengeCrossPoint(
            PointCollection ptList, Point ptCenter, Point ptOuter)
        {
            Point ptResult = ptCenter;
            if ((ptList != null) && (ptList.Count >= 2))
            {
                // 逐条边判断，计算两条线段的交点
                for (int nIndex = 0; nIndex < ptList.Count - 1; nIndex++)
                {
                    ptResult = GetCrossPoint(
                        ptList[nIndex], ptList[nIndex + 1], ptCenter, ptOuter);
                    if (!Double.IsNaN(ptResult.X))
                    {
                        break;
                    }
                }
                if (Double.IsNaN(ptResult.X))
                {
                    ptResult = GetCrossPoint(
                        ptList[0], ptList[ptList.Count - 1], ptCenter, ptOuter);
                }
            }
            if (Double.IsNaN(ptResult.X))
            {
                ptResult = ptCenter;
            }
            return ptResult;
        }

        /// <summary>
        /// 计算矩形控件中心到指定点的线段与矩形控件边界的交点
        /// 如果指定点在矩形控件中间则返回矩形控件中心坐标
        /// </summary>
        /// <param name="ptCenter">中心坐标</param>
        /// <param name="dWidth">控件宽度</param>
        /// <param name="dHeight">控件高度</param>
        /// <param name="ptOuter">指定的任意一点</param>
        /// <returns>中心坐标到指定点的线段与矩形控件边界的交点</returns>
        public static Point GetRectangleCrossPoint(
            Point ptCenter, double dWidth, double dHeight, Point ptOuter)
        {
            Point ptResult = ptCenter;
            double dHalfWidth  = dWidth / 2;
            double dHalfHeight = dHeight / 2;
            // 四个顶角
            Point ptLeftTop = new Point(ptCenter.X - dHalfWidth, ptCenter.Y - dHalfHeight);
            Point ptRightTop = new Point(ptCenter.X + dHalfWidth, ptCenter.Y - dHalfHeight);
            Point ptRightBottom = new Point(ptCenter.X + dHalfWidth, ptCenter.Y + dHalfHeight);
            Point ptLeftBottom = new Point(ptCenter.X - dHalfWidth, ptCenter.Y + dHalfHeight);
            ptResult = GetCrossPoint(ptLeftTop, ptRightTop, ptCenter, ptOuter);
            if (Double.IsNaN(ptResult.X))
            {
                ptResult = GetCrossPoint(ptRightTop, ptRightBottom, ptCenter, ptOuter);
            }
            if (Double.IsNaN(ptResult.X))
            {
                ptResult = GetCrossPoint(ptRightBottom, ptLeftBottom, ptCenter, ptOuter);
            }
            if (Double.IsNaN(ptResult.X))
            {
                ptResult = GetCrossPoint(ptLeftBottom, ptLeftTop, ptCenter, ptOuter);
            }
            if (Double.IsNaN(ptResult.X))
            {
                ptResult = ptCenter;
            }
            // 如果是圆角矩形,这里实际上应该额外计算一下圆角处的坐标,不过这里忽略了
            return ptResult;
        }
        #endregion
    }
}


